package com.ruoyi.system.utils;


import com.ruoyi.system.anno.NeedComparedProperty;
import com.ruoyi.system.domain.ModifiedDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @Version: 1.0
 * @Description: 实体类属性对比工具, 比较两个实体类同名属性值不同之处 约束: 比较字符串类型属性
 */

@Slf4j
@Component
public class ComparePropertyUtils {
    public static List<ModifiedDTO> getDiff(Object o1, Object o2) {
        List<ModifiedDTO> diffList = new ArrayList<>();
        Class<?> o1Clazz = o1.getClass();
        Class<?> o2Clazz = o2.getClass();
        Field[] declaredFields = o1Clazz.getDeclaredFields();
        for (int i = 0; i < declaredFields.length; ++i) {
            Field field = declaredFields[i];
            NeedComparedProperty annotation = field.getAnnotation(NeedComparedProperty.class);
            if (annotation == null) {
                continue;
            }
            Object invokeO1, invokeO2;
            try {
                PropertyDescriptor pdo1 = new PropertyDescriptor(field.getName(), o1Clazz);
                PropertyDescriptor pdo2 = new PropertyDescriptor(field.getName(), o2Clazz);
                Method readMethod1 = pdo1.getReadMethod();
                Method readMethod2 = pdo2.getReadMethod();
                invokeO1 = readMethod1.invoke(o1);
                invokeO2 = readMethod2.invoke(o2);
            } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                log.error("获取bean属性值错误, 提示: [{}]", e.getMessage());
                continue;
            }
            if (!(invokeO1 == null && invokeO2 == null) && (invokeO1 != null && !invokeO1.equals(invokeO2) || !invokeO2.equals(invokeO1))) {
                ModifiedDTO modifiedDTO = new ModifiedDTO();
                modifiedDTO.setName(StringUtils.isBlank(annotation.name()) ? field.getName() : annotation.name());
                modifiedDTO.setBefore(Optional.ofNullable(invokeO1).orElse(""));
                modifiedDTO.setAfter(Optional.ofNullable(invokeO2).orElse(""));
                diffList.add(modifiedDTO);
            }
        }
        return diffList;
    }

    public static Object transferNull(Object o) {
        Class<?> clazz = o.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (int i = 0; i < declaredFields.length; ++i) {
            Field field = declaredFields[i];
            field.setAccessible(true);
            try {
                PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), clazz);
                Method readMethod = descriptor.getReadMethod();
                Method writeMethod = descriptor.getWriteMethod();
                Object oValue = readMethod.invoke(o);
                if (oValue == null) {
                    String typeName = field.getType().getName();
                    switch (typeName) {
                        case "java.lang.String":
                            writeMethod.invoke(o, "");
                            break;
                        case "java.util.List":
                            writeMethod.invoke(o, Collections.EMPTY_LIST);
                            break;
                        case "java.util.Map":
                            writeMethod.invoke(o, Collections.EMPTY_MAP);
                            break;
                        default:
                            break;
                    }
                }

            } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                log.error("获取bean属性值错误, 提示: [{}]", e.getMessage());
                continue;
            }
        }
        return o;
    }
}
